package com.meixun.xuanke.course.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.meixun.xuanke.course.dao.CourseDao;
import com.meixun.xuanke.course.exception.MessageException;
import com.meixun.xuanke.course.model.Course;
import com.meixun.xuanke.course.model.MqCourseInfo;
import com.meixun.xuanke.course.model.User;
import com.meixun.xuanke.course.service.ActiveMQService;
import com.meixun.xuanke.course.service.CourseService;
import com.meixun.xuanke.course.util.CourseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class CourseServiceImpl implements CourseService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    ActiveMQService activeMQService;

    @Resource
    private CourseDao courseDao;
    @Override
    public JSONObject getConfig(String schoolId,Integer termTypeid) {
        if(termTypeid==null){
            termTypeid=queryTermOne();
        }
        String  key = "config:getConfig_schoolId_" + schoolId+"_termTypeid_"+termTypeid;
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            JSONObject object=JSONObject.parseObject(redisTemplate.opsForValue().get(key).toString());
            return object;
        }
        HashMap<String, Object> object =courseDao.getConfig(schoolId);
        if(object==null){
            return null;
        }
        try {
            JSONObject  configJson=JSONObject.parseObject(object.get("configJson")+"");
            if(termTypeid!=null){
                HashMap<String, Object> termTypeObject =courseDao.getXTermType(termTypeid);
                try {
                    JSONObject  termTypeConfigJson=JSONObject.parseObject(termTypeObject.get("configJson")+"");
                    if(termTypeConfigJson!=null){
                        Set<String> keySet= termTypeConfigJson.keySet();
                        for (String jsonkey : keySet) {
                            configJson.put(jsonkey,termTypeConfigJson.get(jsonkey));
                        }
                        object.put("configJson",configJson);
                    }
                }catch (Exception e){ }
            }
            redisTemplate.opsForValue().set(key, configJson.toJSONString(), 600, TimeUnit.SECONDS);
            return configJson;
        }catch (Exception e){
            return null;
        }

    }

    /**
     * 查询学期
     * @return
     */
    @Override
    public Integer queryTermOne() {
        String key = "term:Newest";
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            Integer object=(Integer)redisTemplate.opsForValue().get(key);
            return object;
        }
        List< HashMap<String,Object>> list =courseDao.queryTermOne();
        if(list.size()>0){
            Integer id= (Integer) list.get(0).get("TermID");
            redisTemplate.opsForValue().set(key, id, 600, TimeUnit.SECONDS);
            return id;
        }else {
            return null;
        }

    }

    @Override
    public Object querySubType(String schoolId) {
        String key = "subType:"+schoolId;
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            Object object=redisTemplate.opsForValue().get(key);
            return object;
        }
        Object object =courseDao.querySubType(schoolId);
        redisTemplate.opsForValue().set(key, object, 600, TimeUnit.SECONDS);
        return object;
    }

    @Override
    public Object queryCourseListByStu(User user) {
        Integer termid=queryTermOne();
        String key="courseList:"+user.getSchoolId()+":"+termid;
        List<Course> list=new ArrayList<>();
        Set set=getMyCourseSet(user);
        boolean hasKey = redisTemplate.hasKey(key);
        if(hasKey){
            list=(List<Course>) redisTemplate.opsForValue().get(key);
        }
        for (int i = 0; i <list.size(); i++) {
            if (!("#"+list.get(i).getGrade()+"#").contains("#"+user.getGrade()+"#")){
                //如果不满足年级限制
                list.remove(i);
                i--;
            }else{
                //判断是否自己已选
                list.get(i).setChecked(set.contains(list.get(i).getId().toString())?1:0);
                long size=getSize(list.get(i).getId());
                list.get(i).setSize(size==-1?list.get(i).getSize():size);
            }
        }
        return list;
    }

    @Override
    public List<Course> getMyCourseList(User user) {
        String key="studentCourseList:"+user.getStuUserId();
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            List<Course> courseList=(List<Course>) redisTemplate.opsForValue().get(key);
            for (int i = 0; i <courseList.size() ; i++) {
                long size=getSize(courseList.get(i).getId());
                courseList.get(i).setSize(size==-1?courseList.get(i).getSize():size);
            }
            return courseList;
        }
        Integer termid=queryTermOne();
        List<Course> courseList=courseDao.getMyCourseList(user.getStuUserId(),user.getSchoolId(),termid);
        redisTemplate.opsForValue().set(key, courseList, 600, TimeUnit.SECONDS);
        return courseList;
    }

    @Override
    public int getMyCourseSize(User user) {
        List<Course> list= getMyCourseList(user);
        return list.size();
    }

    /**
     * 更新所有选课学校的课程列表
     */
    @Override
    public void updateCoureseList() {
        List<HashMap<String,Object>> schoolList=courseDao.getCourseSchoolList();
        for (HashMap school:schoolList) {
            String schoolid= school.get("schoolid")+"";
            Integer termid=queryTermOne();
            String key="courseList:"+schoolid+":"+termid;
            //查询学校当前学期课程
            List<Course> courseList =courseDao.queryCourseListBySchool(schoolid,termid);
            //缓存课程列表
            redisTemplate.opsForValue().set(key,courseList);
            for (int i = 0; i <courseList.size(); i++) {
                String keyDetail="courseDetail:"+courseList.get(i).getId();
                String keySize="courseSize:"+courseList.get(i).getId();
                Course course=courseDao.getCourseById(courseList.get(i).getId());
                course.setSize(courseList.get(i).getSize());
                redisTemplate.opsForValue().set(keyDetail,course);
                redisTemplate.opsForValue().set(keySize,course.getSize());
            }
            logger.info(key+" 课程缓存列表已经更新");
        }
    }
    private long getSize(Integer id){
        String keySize="courseSize:"+id;
        if(redisTemplate.hasKey(keySize)){
            return (long)redisTemplate.opsForValue().get(keySize);
        }else {
            long size=courseDao.getCourseSize(id);
            redisTemplate.opsForValue().set(keySize,size);
            return size;
        }
    }

    @Override
    public Course getCourseDetail(Integer id,User user) {
        String key="courseDetail:"+id;
        boolean hasKey = redisTemplate.hasKey(key);
        if(hasKey){
            Course course=(Course)redisTemplate.opsForValue().get(key);
            long size=getSize(course.getId());
            course.setSize(size==-1?course.getSize():size);
            Set set=getMyCourseSet(user);
            course.setChecked(set.contains(course.getId().toString())?1:0);
            return course;
        }
        throw  new MessageException("当前课程信息不存在或当前选课已结束");
    }

    @Override
    public int addCourse(Integer id, User user) {
        String key ="addCourse:"+id+":"+user.getStuUserId();
        Course course=getCourseDetail(id,user);
        CourseUtil.checkTime(course,new Date());
        //初步过滤
        if (!("#"+course.getGrade()+"#").contains("#"+user.getGrade()+"#")){
            //如果不满足年级限制
            throw  new MessageException("选课失败，当前课程年级不符合");
        }
        //是否已选
        if(course.getChecked()==1){
            throw  new MessageException("您已选当前课程，请勿重复提交");
        }
        if(course.getSize()>=course.getMaxsize()){
            throw  new MessageException("选课失败，当前课程人数已满，请选择其他课程");
        }
        if(course.getType()==0){
            throw  new MessageException("选课失败，当前课程不支持学生操作，请选择其他课程（105）");
        }

        if(redisTemplate.hasKey(key)){
            String result=(String) redisTemplate.opsForValue().get(key);
            if(result.equals("0")){
                throw  new MessageException("系统已有您当前课程正则处理中,请尝试刷新页面查看结果（105）");
            }

        }
        List<Course> courseList= getMyCourseList(user);
        Integer termid=queryTermOne();
        JSONObject configJson= getConfig(user.getSchoolId(),termid);

        for (int i = 0; i <courseList.size() ; i++) {
            Course course1=courseList.get(i);
            if(course1==null||course1.getId()==null){
                continue;
            }
            if(course1.getSubId()==course.getSubId()){
                throw  new MessageException("选课失败，您已选择同科目课程，请选择其他课程");
            }
            //检测时间冲突
            if (configJson.getIntValue("isCheckTime")==1){
                if(configJson.getIntValue("timeType")==0){
                    if (CourseUtil.isTimeConflict( course1.getTimeText(),course.getTimeText()+"")){
                        throw  new MessageException("选课失败，当前课程和["+course1.getCoursename()+"]课程时间冲突");
                    }
                }else if(configJson.getIntValue("timeType")==1){
                    if (CourseUtil.isTimeConflict( course1.getTimeJson(),course.getTimeJson()+"")){
                        throw  new MessageException("选课失败，当前课程和["+course1.getCoursename()+"]课程时间冲突");
                    }
                }
            }

        }
        //检测课程数量


        //吧状态写入redis
        //0 表示正在选课中

        redisTemplate.opsForValue().set(key,"0");
        //进去选课队列
        MqCourseInfo mqCourseInfo =new MqCourseInfo();
        mqCourseInfo.setCourseid(id);
        mqCourseInfo.setInputer(user.getUserId());
        mqCourseInfo.setSchoolid(user.getSchoolId());
        mqCourseInfo.setStudentid(user.getStuUserId());
        mqCourseInfo.setTermid(termid);
        mqCourseInfo.setState(MqCourseInfo.state_add);
        activeMQService.addCourse(mqCourseInfo);
        return 0;
    }

    @Override
    public int getCourseResult(Integer id, User user,Integer type) {
        String key ="addCourse:"+id+":"+user.getStuUserId();
        if(type==1){
            key ="removeCourse:"+id+":"+user.getStuUserId();
        }
        if( redisTemplate.hasKey(key)){
            String result=(String) redisTemplate.opsForValue().get(key);
            if("0".equals(result)){
                throw  new MessageException(2000,"正在处理中，请稍后");
            }else if("200".equals(result)){
                //操作成功
                return 0;
            }else{
                throw  new MessageException(result);
            }
        }else{
            throw  new MessageException("选课系统繁忙，请稍后再试");
        }
    }

    @Override
    public int removeCourse(Integer id, User user) {
        String key ="removeCourse:"+id+":"+user.getStuUserId();
        Integer termid=queryTermOne();
        Course course=getCourseDetail(id,user);
        CourseUtil.checkTime(course,new Date());
        if(course.getType()==0){
            throw  new MessageException("退课失败，当前课程不支持学生操作（105）");
        }
        redisTemplate.opsForValue().set(key,"0");
        //进去选课队列
        MqCourseInfo mqCourseInfo =new MqCourseInfo();
        mqCourseInfo.setCourseid(id);
        mqCourseInfo.setInputer(user.getUserId());
        mqCourseInfo.setSchoolid(user.getSchoolId());
        mqCourseInfo.setStudentid(user.getStuUserId());
        mqCourseInfo.setTermid(termid);
        mqCourseInfo.setState(MqCourseInfo.state_remove);
        activeMQService.addCourse(mqCourseInfo);
        return 0;
    }

    /**
     * 查询学生的课程集合
     * @param user
     * @return
     */
    Set getMyCourseSet(User user){
        String key="studentCourseIds:"+user.getStuUserId();
        if (!redisTemplate.hasKey(key)){
            Integer termid=queryTermOne();
            String ids =courseDao.getMyCourseIds(user.getStuUserId(),user.getSchoolId(),termid);
            if (ids==null){
                ids="";
            }
            redisTemplate.opsForSet().add(key,ids.split(","));
        }
        Set set=redisTemplate.opsForSet().members(key);
        return set;
    }
}
